
class Student():
    #类变量：定义在这里是类变量，可以由类名直接调用，也可以由对象来调用
    status = "类变量：学生身份"
    area = "类变量：学校"
    motto = "类变量：好好学习，天天向上"
    sum  = 0
    
    #构造函数：特殊的实例方法(带有"_init__")，用以创建实例对象
    def __init__(self,name,gender1="男", age=18,score= 0):
        #实例变量：构造函数中通过self绑定，设置成员变量
        self.name = name
        self.gender = gender1
        self.age = age

        #实例方法内访问实例变量，需要使用self，对比下面四行代码
        #第二行代码，虽然不使用self也打印了相同的值，但其实打印的是形参name
        #比如修改形参为gender1后再直接打印gender，就会显示报错
        print(self.name) 
        print(name)      
        #print(self.gender)
        #print(gender)   #'gender' is not defined,报错

        #实例方法中访问类变量的两种方法
        print(Student.status)    
        print(self.__class__.status)


    #实例方法：第一个参数必须是self
    def introSelf(self):
        print("------我是一名学生，我的信息是：------")
        print("我的名字：" + self.name) #访问实例变量
        print("我的性别:" + self.gender)
        print("我的年龄" + str(self.age))
        print("我的年龄" + Student.status) #访问类变量

    #类方法：必须是使用@classmethod装饰器的方法才是类方法
    @classmethod
    def plusSum(cls):
        cls.sum += 1
        #print(self.name)  #不能访问实例变量
        print("类方法访问类变量sum：" + str(cls.sum))
        print("类方法访问类变量sum：" + str(Student.sum))

    #静态方法：
    @staticmethod
    def testStaticMethod():
        #print(self.name)  #不能访问实例变量
        print("静态方法访问类变量sum：" + str(Student.sum))


#测试1：创建实例对象，并调用类方法
stu1 = Student("小明")        #创建Student实例
stu1.introSelf()             #调用实例的公开方法

Student.plusSum()            #调用类方法，增加学生计数
print(Student.motto)         #通过类名访问类变量
print(stu1.__class__.motto)  #通过实例访问类变量

stu1.testValue = "testValue" #外部实例直接增加原不存在的实例属性
print(stu1.testValue)


# stu2 = Student("小红")
# Student.plusSum()

# stu3 = Student("小丽")
# Student.plusSum()

#测试2：调用静态方法
# Student.testStaticMethod()

#测试3
#__dict可以打印类或示例中的属性有哪些
# print(Student.__dict__)
# print(stu.__dict__)



'''
一、构造函数
构造函数是通过特殊的_init__方法来创建实例对象的方法，它具有以下特点
1.传入的第一个参数必须是self,表示创建的实例本身；
2.构造函数与普通方法一样，如果没有return值，默认是返回none；
3.构造函数在创建对象时会自动调用，也可以主动调用但是不常用；

二、类变量与实例变量
类变量：直接定义在类中的变量
通过类名访问："类名.类变量名",如"Student.motto"
通过实例访问："实例名.__class_.类变量名"，如"stu1.__class__.motto"

实例变量：实例变量是和具体实例相关的变量，所以只能被实例访问，有两种方法添加实例变量
构造方法中：在构造函数中可通过self绑定，会增加新的实例属性
实例绑定：通过外部创建的实例直接绑定，会增加新的实例属性，如：stu1.testValue = "testValue"


二、实例方法与类方法
实例方法是在类中定义的用于描述实例行为的函数，它具有以下特点：
1.实例方法参数中必须添加self关键字，否则报错，但是调用方法的时候不需要传入self;
2.self用于表示当前实例，用于访问实例属性；
3.self可以使用this等其他变量名替换，但是不推荐这样做；
4.实例方法只能被创建后的实例调用，而不能像类方法一样通过类名调用；

类方法具有以下特点：
1.类方法的方法名上必须用装饰器"@classmethod"标记,第一个参数必须是cls；
2.cls用于表示当前类，用于访问类变量，操作与实例无关的行为；
3.cls也可以换成self等其他变量名替换，但不推荐这样做；
4.类方法通过类名直接调用，也可以被实例调用(但不推荐)
5.类方法中只能访问类变量(通过cls或者类名)，不能访问实例变量

三、静态方法
1.静态方法的方法名上必须用装饰器"@staticmethod"标记，参数不限制
2.静态方法可以被类或者实例调用
3.静态方法只能访问类变量(通过类名)，不能访问实例变量
4.静态方法功能与类方法功能相似，但又与面向对象本身关联不大，所以不推荐经常用；


四、变量查找顺序
当我们需要在外部通过实例来访问它的实例变量时，Python返回该变量的顺序如下：
1.Python会根据变量名在实例中查找此变量，如果存在就会直接返回该变量；
2.如果对象中不存在此变量，且类中存在同名的类变量，则返回此类变量；
3.如果类变量也不存在，就会继续在父类中寻找，直至找到返回或者查无此变量；
4.注意：此查找顺序只在外部访问实例变量时有效，实例方法内部访问实例便量不符合此规则

'''

